#include <std.h>
#include <pio.h>
#include <system.h>
#include <error.h>
#include <type.h>
#include <dint.h>

#define APM_SWINT 0x15
#define APM_INST 0x5300
#define APM_CONNECTRM 0x5301
#define APM_C16PM 0x5302
#define APM_DISCONNECT 0x5304
#define CPU_IDLE 0x5305
#define CPU_BUSY 0x5306
#define APM_PWRSTATE 0x5307
#define APM_ED 0x5308
#define RESTORE_DEF 0x5309
#define APM_DRVVER 0x530e

#define dev_idBIOS 0
#define dev_idALL 1
#define dev_idDISPLAY 0x1ff
#define dev_idSECSTR 0x2ff
#define dev_idPARALLEL 0x3ff
#define dev_idSERIAL 0x4ff
#define dev_idNETADAP 0x5ff
#define dev_idPCMCIA 0x6ff

#define stateREADY 0
#define stateSTANDBY 1
#define stateSUSPEND 2
#define stateOFF 3

static struct apm_inst	{
	u8 majv;
	u8 minv;
	u16 flags;
	u8 errc;
}apm_inst;

int apm_installed()
{
	if(apm_inst.errc==NULL)
		return 1;
	return NULL;
}

#define u16pm ((apm_inst.flags)&1)
#define u32pm (((apm_inst.flags)&2)>>1)
#define idlespeedlo (((apm_inst.flags)&4)>>2)
#define apmdisabled (((apm_inst.flags)&8)>>3)
#define apmdisengaged (((apm_inst.flags)&16)>>4)

#define apm_call(func,dev_id,state) bioscall(func,dev_id,state,0,0,0,APM_SWINT)

int get_apm_info()
{
	u8 cf;
	apm_call(APM_INST,0,0);
	cf=f&1;
	if(cf)	{
		apm_inst.errc=(u8)(ax>>8);
		return apm_inst.errc;
	}
	apm_inst.majv=(u8)(ax>>8);
	apm_inst.minv=(u8)(ax);
	apm_inst.flags=cx;
	apm_inst.errc=NULL;
	return NULL;
}

int connect_rm()
{
	u8 cf;
	if(apm_inst.errc!=NULL)
		return -1;
	apm_call(APM_CONNECTRM,0,0);
	cf=f&1;
	if(cf)	{
		apm_inst.errc=(u8)(ax>>8);
		return apm_inst.errc;
	}
	return NULL;
}

int disconnect()
{
	apm_call(APM_DISCONNECT,0,0);
	return NULL;
}



int cpu_idle()
{
	apm_call(CPU_IDLE,0,0);
	return NULL;
}



int cpu_busy()
{
	apm_call(CPU_BUSY,0,0);
	return NULL;
}


int set_power_state(u16 dev_id,u16 state)
{
	apm_call(APM_PWRSTATE,dev_id,state);
	return NULL;
}

int enable_apm(u16 dev_id)
{
	apm_call(APM_ED,dev_id,1);
	return NULL;
}

int disable_apm(u16 dev_id)
{
	apm_call(APM_ED,dev_id,0);
	return NULL;
}

int restore_def(u16 dev_id)
{
	apm_call(RESTORE_DEF,dev_id,0);
	return NULL;
}

int driver_ver(u16 dev_id,u16 ver)
{
	apm_call(APM_DRVVER,dev_id,ver);
	return NULL;
}

int apm_poweroff()
{
	cli();
	disable_irq(0);
	disable_irq(1);
	disconnect();
	connect_rm();
	driver_ver(0,0x0101);
	set_power_state(dev_idALL,stateOFF);
	mdelay(500);
		i_error("Failed system shutdown!");
}

int init_apm()
{
	printdev("\nFinding Advanced Power Management");
	get_apm_info();
	if(apm_inst.errc==NULL)
		printdev("\nAPM Version: %d.%d",apm_inst.majv,apm_inst.minv);
	else
		printdev("\nNo APM");
	return SUCCESS;
}

kdrv apm={
	.name="apm",
	.init=init_apm,
	.reset=NULL,
	.deinit=NULL,
	.select_subdevice=NULL,
	.read_char=NULL,
	.read_block=NULL,
	.write_char=NULL,
	.write_block=NULL,
};

